package com.idroc.coelacanth.locate.support;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.SortedMap;
import java.util.TreeMap;

import com.idroc.coelacanth.locate.HashAlgorithm;
import com.idroc.coelacanth.locate.ServiceLocator;

/**
 * 服务定位器工厂
 * @author yuyoo (yuyoo4j@163.com)
 * @date Dec 12, 2009 2:51:16 PM
 */
public final class ServiceLocators {


	/**
	 * 防止类被非法实例化
	 */
	private ServiceLocators() {}
	
	/**
	 * 随机算法 服务定位器
	 * @author yuyoo (yuyoo4j@163.com)
	 * @date Dec 10, 2009 11:19:51 PM
	 */
	public static class RandomServiceLocator implements ServiceLocator {
		
		@SuppressWarnings("unused")
		private HashAlgorithm h = null;
		
		private List<Object> services = null;
		
		private final Random random = new Random();

		public Object lookup(String key, int strategyCode) { 
			
			int next = random.nextInt(services.size());
			return services.get(next);
		}

		public void setHashAlgorithm(HashAlgorithm hash) {

			this.h = hash;
		}

		public void setNodes(Map<Integer, Object> services) { 

			this.services = new ArrayList<Object>(services.size());
			for (Integer key : services.keySet()) {
				this.services.add(services.get(key));
			}
		} 
	}
	
	/**
	 * 取模算法 服务定位器
	 * @author yuyoo (yuyoo4j@163.com)
	 * @date Dec 10, 2009 11:17:32 PM
	 */
	public static class ModServiceLocator implements ServiceLocator {
		
		public static final int MAP_SIVE_LOOKUP_STRATEGY = 11111; // 随机赋值
		public static final int MAP_KEY_LOOKUP_STRATEGY = 11112; // 随机赋值
		
		protected boolean strategy = false;
		
		protected int defaultStrategyCode = ServiceLocator.NULL_STRATEGY_CODE;
		
		protected HashAlgorithm h = null;
		
		protected SortedMap<Integer, Object> serviceMap = null;
		
		protected List<Object> serviceList = null;
		
		
		public ModServiceLocator(boolean strategy, int defaultStrategy) {
			
			this.strategy = strategy;
			this.defaultStrategyCode = defaultStrategy;
		}
		
		public ModServiceLocator() {
			
			this(false, MAP_SIVE_LOOKUP_STRATEGY);
		}
		
		public Object lookup(String key, int strategyCode) {

			int code = strategy ? strategyCode : defaultStrategyCode;
			switch (code) {
			
			case MAP_SIVE_LOOKUP_STRATEGY:
				int k = h.hash(key);
				int index = Math.abs(k % serviceList.size());
				return serviceList.get(index);
			case MAP_KEY_LOOKUP_STRATEGY:
				int kk = Integer.valueOf(key).intValue();
				int idx = Math.abs(kk % (serviceMap.lastKey().intValue() + 1));
				return serviceMap.get(Integer.valueOf(idx));
			default:
				return null;
			}
		}

		public void setHashAlgorithm(HashAlgorithm hash) {
			
			this.h = hash;
		}

		public void setNodes(Map<Integer, Object> services) {
	 
			serviceMap = new TreeMap<Integer, Object>(services);
			serviceList = new ArrayList<Object>(services.size());
			
			for(Integer key : serviceMap.keySet()) {
				serviceList.add(serviceMap.get(key));
			}
		}

	}
	
	public static class ConsistentHashServiceLocator implements ServiceLocator {
		
		protected HashAlgorithm h = null;
		
		protected SortedMap<Integer, Object> services = null;

		public Object lookup(String key, int strategyCode) {

			Integer k = Integer.valueOf(h.hash(key));
			Object s = services.get(k);
			if (null == s) {
				SortedMap<Integer, Object> tails = services.tailMap(k);
				if (tails.isEmpty()) {
					s = services.get(services.firstKey());
				} else {
					s = services.get(tails.firstKey());
				}
			}
			return s;
		}

		public void setHashAlgorithm(HashAlgorithm hash) {

			this.h = hash;
		}

		public void setNodes(Map<Integer, Object> services) {
			
			this.services = new TreeMap<Integer, Object>(services);
		} 
	}
	
	public static class NestedServiceLocator implements ServiceLocator {
	 	
		protected ServiceLocator innerLocator = null;
		
		public NestedServiceLocator(ServiceLocator locator) {
			this.innerLocator = locator;
		}

		public Object lookup(String key, int strategyCode) {
			
			ServiceLocator locator = innerLocator;
			Object s = locator.lookup(key, strategyCode);
			while (s instanceof ServiceLocator) {
				locator = (ServiceLocator)s;
				s = locator.lookup(key, strategyCode);
			}
			return s;
		}

		public void setHashAlgorithm(HashAlgorithm hash) {

			this.innerLocator.setHashAlgorithm(hash);
		}

		public void setNodes(Map<Integer, Object> services) {
			 
			this.innerLocator.setNodes(services);
		}

	}

}
